package com.xxpt.common.util;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;
import com.xxpt.common.enums.FileUploadType;
import com.xxpt.common.utils.Tools;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;

@Component
public class OssUploadUtil {

    private static final Logger logger = LoggerFactory.getLogger(OssUploadUtil.class);

    /**
     * 头像保存路径
     */
    public static final String IMAGE_HEAD_STUDENT = "images/head/";
    /**
     * 统一社会信用证件
     */
    public static final String UNIFIED_SOCIAL_CREDIT_CODE = "images/unifiedSocialCreditCode/";

    static  String  endpoint = "http://oss-cn-beijing.aliyuncs.com";
    /**
     *  云账号AccessKey有所有API访问权限，建议遵循阿里云安全最佳实践，创建并使用RAM子账号进行API访问或日常运维，请登录 https://ram.console.aliyun.com 创建
     */
    static String accessKeyId;
    static String accessKeySecret;
    /**
     * 在oss上的存储空间
     */
    static String buckName;

    @Value("${aliyun.oss.buckname}")
    public void setBuckName(String buckName) {
        OssUploadUtil.buckName = buckName;
    }

    public static String getBuckName() {
        return buckName;
    }

    @Value("${aliyun.oss.admin}")
    public void setAccessKeyId(String accessKeyId) {
        OssUploadUtil.accessKeyId = accessKeyId;
    }

    @Value("${aliyun.oss.password}")
    public void setAccessKeySecret(String accessKeySecret) {
        OssUploadUtil.accessKeySecret = accessKeySecret;
    }

    @Value("${aliyun.oss.endpoint}")
    public void setDndpoint(String endpoint) {
        OssUploadUtil.endpoint = endpoint;
    }


    public static OSSClient getOSSClient(){
        OSSClient myOss = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        return myOss;
    }

    /**
     * 简单文件上传通过输入流
     *
     * @param is       文件输入流
     * @param fileName 文件名
     * @return 返回结果
     */
    public String simpleUploadByInputStream(InputStream is, String fileName) {
        OSS client = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        client.putObject(new PutObjectRequest(buckName, fileName, is));
        boolean b = client.doesObjectExist(buckName, fileName);
        //官方文档没找到特别好的返回外网URL地址的方法，虽然有一个client.generatePresignedUrl()方法，但这个方法必须传入过期时间。如果有更好的实现，欢迎留言告知。谢谢~
        client.shutdown();
        // 拼接url链接
        return b ? "http://" + buckName + "." + endpoint.substring(7) + "/" + fileName : "";
    }


    public static String createBucketName(OSSClient ossClient, String bucketName) {
        // 存储空间
        final String bucketNames = bucketName;
        if (!ossClient.doesBucketExist(bucketName)) {
            // 创建存储空间
            /* 通过一个Bucket对象来创建 */
            CreateBucketRequest bucketObj = new CreateBucketRequest(bucketName);// 构造函数入参为Bucket名称，可以为空
            bucketObj.setCannedACL(CannedAccessControlList.PublicRead);// 设置bucketObj访问权限acl
            Bucket bucket =  ossClient.createBucket(bucketObj);// 创建Bucket
//            Bucket bucket = ossClient.createBucket(bucketName);
            logger.info("创建存储空间成功");
            return bucket.getName();
        }
        return bucketNames;
    }

    /**
     * 上传文件
     * @param file
     * @return
     */
    public static OssUploadUtil.UploadFileInfo upladFile(MultipartFile file, FileUploadType fileUploadType) {
        String originalFilename = file.getOriginalFilename();
//        System.out.println("上传文件" + originalFilename);

        String folder = fileUploadType.getFolder();
        String ext = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        String fileName = Tools.get32UUID() + "." + ext;
        UploadFileInfo  result= OssUploadUtil.uploadObject2OSS(file, OssUploadUtil.buckName, folder, fileName);
        result.setOldName(originalFilename);
        return result;
    }

    /**
     * 创建模拟文件夹
     *
     * @param ossClient
     *            oss连接
     * @param bucketName
     *            存储空间
     * @param folder
     *            模拟文件夹名如"qj_nanjing/"
     * @return 文件夹名
     */
    public static String createFolder(OSSClient ossClient, String bucketName, String folder) {

        bucketName = createBucketName(ossClient,bucketName);
        // 文件夹名
        final String keySuffixWithSlash = folder;
        // 判断文件夹是否存在，不存在则创建
        if (!ossClient.doesObjectExist(bucketName, keySuffixWithSlash)) {
            // 创建文件夹
            ossClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
            logger.info("创建文件夹成功");
            // 得到文件夹名
            OSSObject object = ossClient.getObject(bucketName, keySuffixWithSlash);
            String fileDir = object.getKey();
            return fileDir;
        }
        return keySuffixWithSlash;
    }

    /**
     * 获得url链接
     *
     * @param key
     *            文件在oos上的路径
     * @return
     */
    public static String getUrl(OSSClient ossClient, String bucketName, String key) {
        // 设置URL过期时间为10年 3600l* 1000*24*365*10
        Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 10);
        // 生成URL
        URL url = ossClient.generatePresignedUrl(bucketName, key, expiration);

        if (url != null) {
            return url.toString();
        }
        return null;
    }

    public static String getUrl(String bucketName, String key) {
        StringBuffer bf = new StringBuffer();
        bf.append("https://"+bucketName+".oss-cn-beijing.aliyuncs.com/");
        bf.append(key);
        return bf.toString();
    }

    /**
     * 上传图片至OSS
     * @param is
     *            上传文件（文件全路径如：D:\\image\\cake.jpg）
     * @param bucketName
     *            存储空间
     * @param folder
     *            模拟文件夹名 如"qj_nanjing/"
     * @return String 返回的唯一MD5数字签名
     */
    public static UploadFileInfo uploadObject2OSS(OSSClient ossClient, InputStream is, String bucketName, String folder, String fileName) {
        UploadFileInfo resultInfo = null;
        String resultStr = null;
        try {
            if( StringUtils.isNotBlank(folder) && !folder.endsWith("/")){
                folder = folder+"/";
            }
            createFolder(ossClient, bucketName, folder);
            // 上传文件 (上传文件流的形式)
            PutObjectResult putResult = ossClient.putObject(bucketName, folder + fileName, is);
            // System.out.println("上传解析结构+++++" + putResult);
            // 解析结果
            resultStr = putResult.getETag();
            if (StringUtils.isNotEmpty(resultStr)) {

                String key = folder + fileName;
                String url = getUrl(OssUploadUtil.buckName,key);//getUrl(ossClient, bucketName,key);
                resultInfo = new UploadFileInfo(url,key);
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
        }finally {
            if(ossClient!=null){
                ossClient.shutdown();
                ossClient = null;
            }
        }
        return resultInfo;
    }

    public static UploadFileInfo uploadObject2OSS( InputStream file, String bucketName, String folder,	String fileName) {
        // 以输入流的形式上传文件
        InputStream is;
        OSSClient client = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        try {
            UploadFileInfo resultInfo = uploadObject2OSS( client,file, bucketName, folder, fileName);
            return resultInfo;
        } catch (Exception e) {
            logger.info("上传文件或图片失败：",e);
        }finally {
            if(client!=null){
                client.shutdown();
                client = null;
            }
        }
        return null;
    }

    /**
     * 获取文件下载流
     * @param url oss地址
     */
    public static InputStream getFileStream(String url) {
        InputStream is = null;
        String bucketName = url.substring(0, url.indexOf(".")).replace("https://", "").replaceAll("http://", "");
        String str1 = url.substring(url.indexOf(bucketName));
        String filePath = str1.substring(str1.indexOf("/") + 1);
        try {
            OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
            OSSObject a = ossClient.getObject(bucketName, filePath);
            is = new BufferedInputStream(a.getObjectContent());
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage());
            if (is != null) {
                try {
                    is.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }

        return is;
    }

    /**
     * 上传图片至OSS
     * @param file  上传文件（
     * @param bucketName 存储空间
     * @param folder  模拟文件夹名 如"qj_nanjing/"
     * @return   文件路径
     */
    public static UploadFileInfo uploadObject2OSS(MultipartFile file, String bucketName, String folder, String fileName) {
        // 以输入流的形式上传文件
        InputStream is;
        OSSClient client = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        try {
            is = file.getInputStream();
            UploadFileInfo resultInfo = uploadObject2OSS( client, is, bucketName, folder, fileName);
            return resultInfo;
        } catch (IOException e) {
            logger.info("上传文件或图片异常：",e);
        }finally {
            if(client!=null){
                client.shutdown();
                client = null;
            }
        }
        return null;
    }


    public static class UploadFileInfo {
        // 原图oss访问路径
        private String url;
        // oss 获取图片路径的key （folder+fileName）
        private String key;
        //原文件名称
        private String oldName;
        // 原图相对路径
        private String urlThumbnail;

        public UploadFileInfo(){}
        public UploadFileInfo(String url,String key){
            this.url = url;
            this.key = key;
        }
        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public String getKey() {
            return key;
        }

        public void setKey(String key) {
            this.key = key;
        }

        public String getUrlThumbnail() {
            return urlThumbnail;
        }

        public void setUrlThumbnail(String urlThumbnail) {
            this.urlThumbnail = urlThumbnail;
        }

        public String getOldName() {
            return oldName;
        }

        public void setOldName(String oldName) {
            this.oldName = oldName;
        }
    }

    public static String getSuffix(String fileName){
        String suffix = fileName.substring(fileName.lastIndexOf("."));
        if(suffix.contains("?")){
            suffix = suffix.substring(0,suffix.indexOf("?") );
        }
        return suffix;
    }



    /**
     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
     *
     * @param fileName
     *            文件名
     * @return 文件的contentType
     */
    public static String getContentType(String fileName) {
        // 文件的后缀名
        String fileExtension = fileName.substring(fileName.lastIndexOf("."));
        if (".bmp".equalsIgnoreCase(fileExtension)) {
            return "image/bmp";
        } else if (".gif".equalsIgnoreCase(fileExtension)) {
            return "image/gif";
        } else if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension)
                || ".png".equalsIgnoreCase(fileExtension)) {
            return "image/jpeg";
        } else if (".html".equalsIgnoreCase(fileExtension)) {
            return "text/html";
        }  else if (".txt".equalsIgnoreCase(fileExtension)) {
            return "text/plain";
        }  else if (".vsd".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.visio";
        } else if (".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.ms-powerpoint";
        } else if (".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {
            return "application/msword";
        } else if (".xml".equalsIgnoreCase(fileExtension)) {
            return "text/xml";
        } else if (".pdf".equalsIgnoreCase(fileExtension)) {
            return "application/pdf";
        } else if (".exe".equalsIgnoreCase(fileExtension)) {
            return "application/x-msdownload";
        }
        // 默认返回类型
        return "image/jpeg";
    }

}
